﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace AjaxControlFramework.Reflection
{
    [Serializable]
    public class ReflectiveCacheCollection<T> : Dictionary<string, Dictionary<string, T>> where T : ReflectiveCacheEntry
    {
        //------// Properties \\--------------------------------------------\\
        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <param name="itemName"></param>
        /// <returns></returns>
        /// <remarks>When setting a value, if an cached item already exists with the same name an error will be thrown.</remarks>
        public T this[Type type, string itemName]
        {
            get { return GetCacheItem(type, itemName); }
            set { AddCacheItem(type, itemName, value, true); }
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        /// <remarks>The collection returned is a clone of the reference to the actual internal collection, thus making it write-protected.</remarks>
        public Dictionary<string, T> this[Type type]
        {
            get
            {
                Dictionary<string, T> typeCollection;

                if (base.TryGetValue(type.AssemblyQualifiedName, out typeCollection))
                {
                    return new Dictionary<string,T>(typeCollection); // This makes the property write-protected;
                }
                else
                {
                    return null;
                }
            }
            set
            {
                this[type.AssemblyQualifiedName] = value;
            }
        }
        //------\\ Properties //--------------------------------------------//



        //------// Constructors \\------------------------------------------\\
        public ReflectiveCacheCollection()
        { }
        //------\\ Constructors //------------------------------------------//



        //------// Methods \\-----------------------------------------------\\
        public virtual void AddCacheItem(Type type, string itemName, T cacheItem, bool throwErrorOnDuplicate)
        {
            Dictionary<string, T> typeCollection;

            if (base.TryGetValue(type.AssemblyQualifiedName, out typeCollection))
            {
                if (typeCollection.ContainsKey(itemName) && throwErrorOnDuplicate)
                {
                    throw new ArgumentException(String.Format("A {0} already exists with the same name.", typeof(T).Name));
                }
                else
                {
                    typeCollection[itemName] = cacheItem;
                }
            }
            else
            {
                typeCollection = new Dictionary<string, T>();
                typeCollection[itemName] = cacheItem;

                base[type.AssemblyQualifiedName] = typeCollection;
            }
        }


        public virtual T GetCacheItem(Type type, string itemName)
        {
            Dictionary<string, T> typeCollection;

            if (base.TryGetValue(type.AssemblyQualifiedName, out typeCollection))
            {
                T cacheEntry;

                if (typeCollection.TryGetValue(itemName, out cacheEntry))
                {
                    return cacheEntry;
                }
                else
                {
                    return null;
                }
            }
            else
            {
                return null;
            }
        }
        //------\\ Methods //-----------------------------------------------//
    }
}
